package rpc.netty.http;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.ThreadFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import rpc.bootstrap.conf.BootProperties;
import rpc.core.InitClose;

/*********
 *
 *
 *@author 197
 *@date 2020/8/19 11:43
 *
 **/


@Sharable
public class SelfCheckHttpServer extends ChannelInboundHandlerAdapter implements InitClose {

  private static final Logger logger = LoggerFactory.getLogger(SelfCheckHttpServer.class);
  private int port;
  private boolean nativeNetty = false;
  private ServerBootstrap serverBootstrap;
  private EventLoopGroup bossGroup;
  private EventLoopGroup workerGroup;

  private Channel serverChannel;
  private Environment environment;
  private BootProperties bootProperties;

  public SelfCheckHttpServer setPort(int port) {
    this.port = port;
    return this;
  }


  @Override
  public void init() {
    String linux = "linux";
    String osName = System.getProperty("os.name");
    if (nativeNetty && StringUtils.isNotBlank(osName) && osName.toLowerCase().contains(linux)) {
      nativeNetty = true;
    }
    ThreadFactory bossThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("rpc_nettyHttp_boss_%d").build();
    ThreadFactory workThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("rpc_nettyHttp_worker_%d").build();
    if (nativeNetty) {
      bossGroup = new EpollEventLoopGroup(2, bossThreadFactory);
      workerGroup = new EpollEventLoopGroup(2, workThreadFactory);
    } else {
      bossGroup = new NioEventLoopGroup(2, bossThreadFactory);
      workerGroup = new NioEventLoopGroup(2, workThreadFactory);
    }
    serverBootstrap = new ServerBootstrap();
    serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);

    serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
    serverBootstrap.option(ChannelOption.SO_REUSEADDR, true);
    serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
    serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
    serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel ch) throws Exception {
        //以下代码在 HttpClientPipelineFactory.java getPipeline()中
        ChannelPipeline pipeline = ch.pipeline()
            .addLast("decoder", new HttpRequestDecoder())
            .addLast("encoder", new HttpResponseEncoder())
            .addLast("aggregator", new HttpObjectAggregator(512 * 1024))
            .addLast(SelfCheckHttpServer.this);
      }
    });
  }

  @Override
  public void start() {
    InetSocketAddress addr = new InetSocketAddress(this.port);
    serverChannel = serverBootstrap.bind(addr).syncUninterruptibly().channel();
    logger.info("selfNetty server started on host(*) port(" + port + ")");
  }

  @Override
  public void close() {

  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    writeRes(ctx, "", "ok");
  }

  private void writeRes(ChannelHandlerContext ctx, String url, String res) {

    // 1.设置响应
    FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
        HttpResponseStatus.OK,
        Unpooled.copiedBuffer(res, CharsetUtil.UTF_8));

    resp.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");

    // 2.发送
    // 注意必须在使用完之后，close channel
    ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE);
  }
}
